home *** CD-ROM | disk | FTP | other *** search
/ Openstep 4.2 (Developer) / Openstep Developer 4.2.iso / NextDeveloper / Examples / DriverKit / AMDPCSCSIDriver / AMDPCSCSIDriver_reloc.tproj / AMD_ChipPrivate.m < prev    next >
Encoding:
Text File  |  1996-04-03  |  32.4 KB  |  1,288 lines

  1. /*     Copyright (c) 1994-1996 NeXT Software, Inc.  All rights reserved. 
  2.  *
  3.  * AMD_ChipPrivate.m - methods used only by AMD_Chip module.
  4.  *
  5.  * HISTORY
  6.  * 2 Nov 94    Doug Mitchell at NeXT
  7.  *      Created. 
  8.  */
  9.  
  10. #import "AMD_Chip.h"
  11. #import "AMD_ChipPrivate.h"
  12. #import "AMD_Private.h"
  13. #import "AMD_x86.h"
  14. #import "AMD_Regs.h"
  15. #import "AMD_Types.h"
  16. #import "AMD_ddm.h"
  17. #import "bringup.h"
  18. #import <driverkit/generalFuncs.h>
  19. #import <kernserv/prototypes.h>
  20.  
  21.  
  22. @implementation AMD_SCSI(ChipPrivate)
  23.  
  24. /*
  25.  * Determine if SCSI interrupt is pending.
  26.  */
  27. - (sintPending_t)scsiInterruptPending
  28. {
  29.     unsigned char sstat;
  30.     
  31.     sstat = READ_REG(scsiStat);
  32.     if (sstat & SS_INTERRUPT) {
  33.         return SINT_DEVICE;
  34.     }
  35.     else {
  36.         return SINT_NONE;
  37.     }
  38. }
  39.  
  40. /*
  41.  * Methods invoked upon interrupt. One per legal scState. All assume that 
  42.  * status and interrupt status have been captured in saveStatus and 
  43.  * saveIntrStatus.
  44.  */
  45.  
  46. /*
  47.  * Disconnected - only legal event here is reselection.
  48.  */
  49. - (void)fsmDisconnected
  50. {
  51.     ddm_chip("fsmDisconnected\n", 1,2,3,4,5);
  52.     ASSERT(activeCmd == NULL);
  53.     if(saveIntrStatus & IS_RESELECTED) {
  54.         /*
  55.          * We've been reselected. 
  56.          */
  57.                 
  58.         unsigned char    selectByte;
  59.         unsigned     fifoDepth;
  60.         unsigned char    msg;
  61.     
  62.         /* 
  63.          * Make sure there's a selection byte and an 
  64.          * identify message in the fifo.
  65.          */
  66.         fifoDepth = READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK;
  67.         ddm_chip("reselect: fifoDepth %d\n", fifoDepth, 2,3,4,5);
  68.         if(fifoDepth != 2) {
  69.             ddm_err("reselection, fifoDepth %d\n", fifoDepth, 
  70.                 2,3,4,5);
  71.             IOLog("AMD53C974: Bad FIFO count (%d) on Reselect\n",
  72.                 fifoDepth);
  73.             [self hwAbort:SR_IOST_HW 
  74.                 reason:NULL];
  75.             return;
  76.             
  77.         }
  78.         
  79.         /* 
  80.          * make sure target set his bit.
  81.          */
  82.         if ((selectByte = READ_REG(scsiFifo) &~ (1 << hostId)) == 0) {
  83.             ddm_err("fsmDisconnected: reselection failed"
  84.                 " - no target bit\n", 1,2,3,4,5);
  85.             [self hwAbort:SR_IOST_BV 
  86.                 reason:"No target bit on Reselect"];
  87.             return;
  88.         }
  89.         
  90.         /* 
  91.          * figure out target from bit that's on.
  92.          */
  93.         for (reselTarget = 0; 
  94.              (selectByte & 1) == 0; 
  95.              reselTarget++, selectByte>>=1) {
  96.             continue;
  97.         }
  98.         
  99.         /* 
  100.          * first message byte must be identify.
  101.          */
  102.         msg = READ_REG(scsiFifo);
  103.         if (saveStatus & SS_PARITYERROR) {
  104.             ddm_err("fsmDisconnected: reselected parity error\n",
  105.                 1,2,3,4,5);
  106.             [self hwAbort:SR_IOST_PARITY 
  107.                 reason:"Parity error on Reselect"];
  108.             return;
  109.         }
  110.         if ((msg & MSG_IDENTIFYMASK) == 0) {
  111.             ddm_err("fsmDisconnected: reselection failed - "
  112.                 "bad msg byte (0x%x)\n", msg, 2,3,4,5);
  113.             [self hwAbort:SR_IOST_BV 
  114.                 reason:"Bad ID Message on Reselect"];
  115.             return;
  116.         }
  117.         reselLun = msg & MSG_ID_LUNMASK;
  118.         currMsgInCnt = 0;
  119.         
  120.         /*
  121.          * At this point, the chip is waiting for us to validate 
  122.          * the identify message. If cmd queueing is enabled
  123.          * for this target, the target is waiting to send a queue 
  124.          * tag message, so we have to tell the chip to 
  125.          * drop ACK before we proceed with the reselection. (There
  126.          * may be other msg bytes coming in, like a bogus 
  127.          * "save ptr" from a Syquest drive...)
  128.          *
  129.          * In case of sync mode, we need to load target context right
  130.          * now, before dropping ACK, because the target might go
  131.          * straight to a data in or data out as soon as ACK drops.
  132.          */
  133.         [self targetContext:reselTarget];
  134.         scState = SCS_ACCEPTINGMSG;
  135.         reselPending = 1;
  136.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  137.         WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  138.         ddm_chip("reselPending: target %d lun %d\n",
  139.             reselTarget, reselLun, 3,4,5);
  140.          
  141.     } else if(saveIntrStatus & IS_SCSIRESET) {
  142.         /*
  143.          * TBD - for now ignore, we get one of these by resetting the
  144.          * chip. If an I/O is pending, it'll probably time out.
  145.          * Maybe we want to return SR_IOST_RESET on the pending 
  146.          * command...
  147.          */
  148.         ddm_chip("fsmDisconnected: ignoring reset interrupt\n",
  149.             1,2,3,4,5);
  150.     } else {
  151.         /* 
  152.          * I'm confused.... 
  153.          */
  154.         [self hwAbort:SR_IOST_BV 
  155.             reason:"bad interrupt while disconnected"];
  156.     }
  157. }
  158.  
  159.  
  160. /*
  161.  * One of three things can happen here - the selection could succeed (though
  162.  * with possible imcomplete message out), it could time out, or we can be 
  163.  * reselected.
  164.  */
  165. #define CATCH_SELECT_TO        0
  166.  
  167. - (void)fsmSelecting
  168. {
  169.     unsigned char fifoDepth;
  170.     unsigned char phase;
  171.     IOSCSIRequest *scsiReq = activeCmd->scsiReq;
  172.     
  173.     ddm_chip("fsmSelecting\n", 1,2,3,4,5);
  174.     ASSERT(activeCmd != NULL);
  175.     if (saveIntrStatus & IS_DISCONNECT) {
  176.         /*
  177.          * selection timed-out. Abort this request.
  178.          */
  179.         #if    CATCH_SELECT_TO
  180.         /* DEBUG ONLY */
  181.         if(scsiReq->cdb.cdb_opcode != C6OP_INQUIRY) {
  182.             IOLog("Unexpected Select Timeout\n");
  183.         }
  184.         #endif    CATCH_SELECT_TO
  185.         ddm_chip("***SELECTION TIMEOUT for target %d\n",
  186.             activeCmd->scsiReq->target, 2,3,4,5);
  187.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  188.         scState = SCS_DISCONNECTED;
  189.         scsiReq->driverStatus = SR_IOST_SELTO;
  190.         [self ioComplete:activeCmd];
  191.         activeCmd = NULL;
  192.     }
  193.     else if(saveIntrStatus == (IS_SUCCESSFUL_OP|IS_SERVICE_REQ)) {
  194.  
  195.         ddm_chip("selection seqstep=%d\n", 
  196.             saveSeqStep & INS_STATE_MASK, 2,3,4,5);
  197.         
  198.         switch (saveSeqStep & INS_STATE_MASK) {
  199.             case 0:    
  200.                 /*
  201.              * No message phase. If we really wanted one,
  202.              * this could be significant...
  203.              */
  204.             if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
  205.                 /*
  206.                  * This target can't do command queueing.
  207.                  */
  208.                 [self disableMode:AM_CmdQueue];
  209.             }    
  210.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  211.                 /*
  212.                  * We were trying to do an SDTR.
  213.                  */
  214.                 [self disableMode:AM_Sync];
  215.                 SDTR_State = SNS_NONE;
  216.             }
  217.             
  218.             /*
  219.              * OK, let's try to continue following phase
  220.              * changes.
  221.              */
  222.             scState = SCS_INITIATOR;
  223.             break;
  224.             
  225.             case 3:    /* didn't complete cmd phase, parity? */
  226.             case 4:    /* everything worked */
  227.             case 1:    /* everything worked, SCMD_SELECT_ATN_STOP
  228.                      * case */
  229.             
  230.                 /* 
  231.              * We're connected. Start following the target's phase
  232.              * changes.
  233.              *
  234.              * If we're trying to do sync negotiation,
  235.              * this is the place to do it. In that case, we
  236.              * sent a SCMD_SELECT_ATN_STOP command, and
  237.              * ATN is now asserted (and we're hopefully in
  238.              * msg out phase). We want to send 5 bytes. 
  239.              * Drop them into currMsgOut[] and prime the  
  240.              * msgOutState machine.
  241.              */
  242.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  243.                 [self createSDTR:currMsgOut inboundMsg:NULL];
  244.                 currMsgOutCnt = MSG_SDTR_LENGTH;
  245.                 msgOutState = MOS_WAITING;
  246.             }
  247.             scState = SCS_INITIATOR;
  248.             break;
  249.             
  250.             case 2:    
  251.             /*
  252.              * Either no command phase, or imcomplete message
  253.              * transfer.
  254.              */
  255.             fifoDepth = READ_REG(currFifoState) & 
  256.                 FS_FIFO_LEVEL_MASK;
  257.             phase = saveStatus & SS_PHASEMASK;
  258.             ddm_chip("INCOMPLETE SELECT; fifoDepth %d phase %s\n",
  259.                 fifoDepth, 
  260.                 IOFindNameForValue(phase, scsiPhaseValues),
  261.                 3,4,5);
  262.             if(activeCmd->queueTag != QUEUE_TAG_NONTAGGED) {
  263.                 /*
  264.                  * This target can't do command queueing.
  265.                  */
  266.                 [self disableMode:AM_CmdQueue];
  267.             }    
  268.             
  269.             /*
  270.              * Spec says ATN is asserted if all message bytes
  271.              * were not sent.
  272.              */
  273.             if(fifoDepth > activeCmd->cdbLength) {
  274.                 WRITE_REG(scsiCmd, SCMD_CLR_ATN);
  275.             }
  276.             
  277.             /*
  278.              * OK, let's try to continue following phase
  279.              * changes.
  280.              */
  281.             scState = SCS_INITIATOR;
  282.             break;
  283.  
  284.             default:
  285.             [self hwAbort:SR_IOST_HW 
  286.                 reason:"Selection sequence Error"];
  287.             break;
  288.         }
  289.     }
  290.     else if(saveIntrStatus & IS_RESELECTED) {
  291.         /*
  292.          * We got reselected while trying to do a selection. 
  293.          * Enqueue this cmdBuf on the HEAD of pendingQ, then deal
  294.          * with the reselect. 
  295.          * Tricky case, we have to "deactivate" this command
  296.          * since this hwStart attempt failed.  
  297.          */
  298.         queue_enter_first(&pendingQ, activeCmd, commandBuf *, link);
  299.         [self deactivateCmd:activeCmd];
  300.         ddm_chip("reselect while trying to select target %d\n",
  301.             activeCmd->scsiReq->target, 2,3,4,5);
  302.         activeCmd = NULL;
  303.         scState = SCS_DISCONNECTED;
  304.         
  305.         /*
  306.          * Go deal with reselect.
  307.          */
  308.         [self fsmDisconnected];
  309.     }
  310.     else {
  311.         ddm_err("fsmSelecting: Bogus select/reselect interrupt\n", 
  312.             1,2,3,4,5);
  313.         [self hwAbort:SR_IOST_HW 
  314.             reason: "Bogus select/reselect interrupt"];
  315.         return;
  316.     }
  317.     return;
  318. }
  319.  
  320. /*
  321.  * This one is illegal.
  322.  */
  323. - (void)fsmInitiator
  324. {
  325.     ddm_chip("fsmInitiator\n", 1,2,3,4,5);
  326.     [self hwAbort:SR_IOST_HW reason:"Interrupt as Initiator"];
  327. }
  328.  
  329. /*
  330.  * We just did a SCMD_INIT_CMD_CMPLT command, hopefully all that's left is
  331.  * to drop ACK. Command Complete message is handled in fscAcceptingMsg.
  332.  */
  333. - (void)fsmCompleting
  334. {        
  335.     ddm_chip("fsmCompleting\n", 1,2,3,4,5);
  336.     ASSERT(activeCmd != NULL);
  337.     if(saveIntrStatus & IS_DISCONNECT) {
  338.         ddm_err("unexpected completing disconnect\n",
  339.             1,2,3,4,5);
  340.         return;
  341.     }
  342.     if(saveIntrStatus & IS_SUCCESSFUL_OP) {
  343.         /*
  344.          * Got both status and msg in fifo; Ack is still true.
  345.          */
  346.         if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 2) {
  347.             /*
  348.              * This is pretty bogus - we expect a status and 
  349.              * msg in the fifo. 
  350.                 */
  351.             [self hwAbort:SR_IOST_HW reason:"InitComplete fifo"
  352.                 " level"];
  353.             return;
  354.         }
  355.         activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
  356.         currMsgInCnt = 1;
  357.         currMsgIn[0] = READ_REG(scsiFifo);
  358.         ddm_chip("fsmCompleting: status 0x%x msg 0x%x\n",
  359.             activeCmd->scsiReq->scsiStatus, 
  360.             currMsgIn[0], 3,4,5);
  361.         if (saveStatus & SS_PARITYERROR) {
  362.             ddm_err("fsmCompleting: parity error on msg in\n",
  363.                 1,2,3,4,5);
  364.             [self hwAbort:SR_IOST_PARITY 
  365.                 reason:"Parity error on message in"];
  366.             return;
  367.         }
  368.         scState = SCS_ACCEPTINGMSG;
  369.         WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  370.         return;
  371.     } else {
  372.         /*
  373.          * Must have just got a status byte only. This is kind of
  374.          * weird, but let's try to handle it.
  375.          */
  376.         ddm_err("fsmCompleting: status only on complete\n", 
  377.             1,2,3,4,5);
  378.         if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
  379.             [self hwAbort:SR_IOST_HW 
  380.                 reason:"Bad Fifo level on Cmd Complete"];
  381.             return;
  382.         }
  383.         activeCmd->scsiReq->scsiStatus = READ_REG(scsiFifo);
  384.         if(saveStatus & SS_PARITYERROR) {
  385.             ddm_err("fsmCompleting: parity error on status\n",
  386.                 1,2,3,4,5);
  387.             [self hwAbort:SR_IOST_PARITY 
  388.                 reason:"Parity Error on Cmd Complete"];
  389.             return;
  390.         }
  391.         
  392.         /*
  393.          * Back to watching phase changes. Why the target isn't in 
  394.          * message in we have yet to find out.
  395.          */
  396.         scState = SCS_INITIATOR;
  397.     }
  398. }
  399.  
  400. /*
  401.  * DMA Complete.
  402.  */
  403. - (void)fsmDMAing
  404. {
  405.     u_int bytesMoved;
  406.     
  407.     ddm_chip("fsmDMAing\n", 1,2,3,4,5);
  408.     ASSERT(activeCmd != NULL);
  409.     
  410.     bytesMoved = [self dmaTerminate];
  411.     if(bytesMoved > activeCmd->currentByteCount) {
  412.         ddm_err("fsmDMAing: DMA transfer count exceeeded\n",
  413.             1,2,3,4,5);
  414.         ddm_err("  expected %d, moved %d\n", 
  415.             activeCmd->currentByteCount, bytesMoved, 3,4,5);
  416.         bytesMoved = activeCmd->currentByteCount;
  417.     }
  418.     ((char *)activeCmd->currentPtr) += bytesMoved;
  419.     activeCmd->currentByteCount     -= bytesMoved; 
  420.     if(saveStatus & SS_PARITYERROR) {
  421.         ddm_err("fsmDMAing: SCSI Data Parity Error\n", 1,2,3,4,5);
  422.         [self hwAbort:SR_IOST_PARITY reason:"SCSI Data Parity Error"];
  423.         return;
  424.     }
  425.     /*
  426.      * Back to watching phase changes.
  427.          */
  428.     scState = SCS_INITIATOR;
  429. }
  430.  
  431. /*
  432.  * Just completed the SCMD_TRANSFER_INFO operation for message in. ACK is
  433.  * still true. Stash the current message byte in currMsgIn[] and proceed to
  434.  * fsmAcceptingMsg after a SCMD_MSG_ACCEPTED.
  435.  */
  436. - (void)fsmGettingMsg
  437. {
  438.     BOOL    setAtn = NO;
  439.     
  440.     ASSERT((activeCmd != NULL) || reselPending);
  441.     if(saveIntrStatus & IS_DISCONNECT) {
  442.         ddm_chip("fsmGettingMsg: message In Disconnect\n", 1,2,3,4,5);
  443.         /*
  444.          * This error is handled on return...
  445.          */
  446.         return;
  447.     }
  448.     if((READ_REG(currFifoState) & FS_FIFO_LEVEL_MASK) != 1) {
  449.         ddm_chip("Message In fifo error\n", 1,2,3,4,5);
  450.         [self hwAbort:SR_IOST_HW reason:"Message In fifo error"];
  451.         return;
  452.     }
  453.  
  454.     currMsgIn[currMsgInCnt++] = READ_REG(scsiFifo);
  455.     if(currMsgInCnt > AMD_MSG_SIZE) {
  456.         [self hwAbort:SR_IOST_BV 
  457.             reason:"Too Many Message bytes received"];
  458.     }
  459.     if(saveStatus & SS_PARITYERROR) {
  460.         ddm_err("fsmGettingMsg: parity error on Message In\n", 
  461.             1,2,3,4,5);
  462.         [self hwAbort:SR_IOST_PARITY 
  463.             reason:"parity error on Message In"];
  464.         return;
  465.     }
  466.     ddm_chip("fsmGettingMsg: currMsgIn[%d] = 0x%x (%s)\n", currMsgInCnt-1,
  467.         currMsgIn[currMsgInCnt-1],
  468.         IOFindNameForValue(currMsgIn[currMsgInCnt-1], 
  469.             scsiMsgValues),    4,5);
  470.             
  471.     /*
  472.      * Handle special cases. 
  473.      */
  474.      
  475.     /*
  476.      * 1. If this is the last byte of an unsolicited sync negotiation, 
  477.      *    we have to assert ATN right now. The message is actually
  478.      *    fully parsed, and a response SDTR message created, in
  479.      *    fsmAcceptingMsg.
  480.      *
  481.      *    This parsing is pretty crude; if we come up with other special 
  482.      *    cases, we might rewrite this or come up with some state variables
  483.      *    to help us.
  484.      */
  485.     if((currMsgInCnt >= MSG_SDTR_LENGTH) && (SDTR_State == SNS_NONE)) {
  486.     
  487.         int start = currMsgInCnt - MSG_SDTR_LENGTH;
  488.         
  489.         if((currMsgIn[start] == MSG_EXTENDED) &&
  490.            (currMsgIn[start+1] == (MSG_SDTR_LENGTH - 2)) &&
  491.            (currMsgIn[start+2] == MSG_SDTR)) {
  492.                ddm_chip("UNSOLICITED SDTR IN; setting ATN\n",
  493.                  1,2,3,4,5);
  494.             WRITE_REG(scsiCmd, SCMD_SET_ATN);
  495.             setAtn = YES;
  496.             SDTR_State = SNS_TARGET_INIT;
  497.         }
  498.     }
  499.  
  500.     /*
  501.      * 2. If this was a message reject, it's possible that an extended
  502.      *    message out was prematurely aborted, with ATN still true.
  503.      *    Clear it so we don't do another (needless) message out.
  504.      *    Avoid this, of course, if we set ATN in this method for 
  505.      *    any reason.
  506.      */
  507.     if((currMsgIn[currMsgInCnt - 1] == MSG_MSGREJECT) && 
  508.        (currMsgOutCnt > 1) &&
  509.        !setAtn) {
  510.         ddm_chip("fsmGettingMsg: Message Reject; clearing ATN\n",
  511.             1,2,3,4,5);
  512.         WRITE_REG(scsiCmd, SCMD_CLR_ATN);
  513.     }
  514.     
  515.     /*
  516.      * No need to clear FIFO; its depth was one on entry, and we read
  517.      * the byte. Note that clearing FIFO after the SCS_ACCEPTINGMSG
  518.      * might disturb possible sync data in transfer.
  519.      */
  520.     WRITE_REG(scsiCmd, SCMD_MSG_ACCEPTED);
  521.     scState = SCS_ACCEPTINGMSG;
  522.  
  523. }
  524.  
  525. /*
  526.  * Just finished a message in; Ack is false. If phase is still
  527.  * message in, we're in the midst of an extended message or additional
  528.  * message bytes on reselect. Otherwise, message in is complete;
  529.  * process currMsgIn[].
  530.  */
  531. - (void)fsmAcceptingMsg
  532. {
  533.     unsigned char     phase = saveStatus & SS_PHASEMASK;
  534.     unsigned     index=0;
  535.     perTargetData    *perTargetPtr;
  536.     
  537.     ddm_chip("fsmAcceptingMsg: phase %s\n", 
  538.         IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
  539.     if((phase == PHASE_MSGIN) && !(saveIntrStatus & IS_DISCONNECT)) {
  540.     
  541.         /*
  542.          * More message bytes to follow.
  543.          * We have to qualify with !IS_DISCONNECT to cover the 
  544.          * case of some targets (like the Exabyte tape drive)
  545.          * which bogusly keep CD, IO, and MSG asserted after
  546.          * they drop BSY upon command complete.
  547.          */
  548.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  549.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  550.         scState = SCS_GETTINGMSG; 
  551.         return;
  552.     }
  553.     
  554.     /*
  555.      * Message in complete. Handle message(s) in currMsgIn[].
  556.      */
  557.     if(reselPending) {
  558.     
  559.         /*
  560.          * Only interesting message here is queue tag.
  561.          */
  562.         unsigned char tag = QUEUE_TAG_NONTAGGED;
  563.         
  564.         ASSERT(activeCmd == NULL);
  565.         if(currMsgIn[index] == MSG_SIMPLE_QUEUE_TAG) {
  566.             if(currMsgInCnt < 2) {
  567.                 [self hwAbort: SR_IOST_BV
  568.                 reason:"Queue tag message, no tag"];
  569.                 return;
  570.             }
  571.             tag = currMsgIn[++index];
  572.             index++;
  573.         }
  574.         
  575.         if([self reselect:reselTarget 
  576.                     lun:reselLun 
  577.                 queueTag:tag] == YES) {
  578.             /*
  579.              * Found a disconnected commandBuf to reconnect.
  580.              *
  581.              * IDENTIFY msg implies restore ptrs.
  582.              */
  583.             reselPending = 0;
  584.             ASSERT(activeCmd != NULL);
  585.             activeCmd->currentPtr = activeCmd->savedPtr;
  586.             activeCmd->currentByteCount =  
  587.                 activeCmd->savedByteCount;
  588.             scState = SCS_INITIATOR;
  589.             
  590.             /* 
  591.              * continue to handle possible additional messages
  592.              */
  593.         }
  594.         else {
  595.             IOLog("AMD53C974: Illegal reselect (target %d lun "
  596.                 "%d tag %d)\n", reselTarget, reselLun, tag);
  597.             [self hwAbort: SR_IOST_BV 
  598.                 reason:NULL];
  599.             return;
  600.         }
  601.     }    /* reselect pending */
  602.     
  603.     /*
  604.      * Handle all other messages.
  605.      */
  606.     ASSERT(activeCmd != NULL);
  607.     perTargetPtr = &perTarget[activeCmd->scsiReq->target];
  608.     
  609.     for(; index<currMsgInCnt; index++) {
  610.         switch(currMsgIn[index]) {
  611.         case MSG_CMDCMPLT:
  612.             /*
  613.              * Bus really should be free; we came here from 
  614.              * fsmCompleting.
  615.              */
  616.             if(!(saveIntrStatus & IS_DISCONNECT)) {
  617.                 ddm_err("fsmAcceptingMsg: Command Complete"
  618.                     " but no Disconnect\n", 1,2,3,4,5);
  619.                 [self hwAbort:SR_IOST_BV 
  620.                     reason:"No Disconnect On Command"
  621.                         " Complete"];
  622.                 return;
  623.             }
  624.             
  625.             /*
  626.              * TA DA!
  627.              */
  628.             scState = SCS_DISCONNECTED;
  629.             activeCmd->scsiReq->driverStatus = SR_IOST_GOOD;
  630.             [self ioComplete:activeCmd];
  631.             activeCmd = NULL;
  632.             return;
  633.         
  634.         case MSG_DISCONNECT:
  635.             if(!activeCmd->discEnable) {
  636.                /*
  637.                 * This could be handled in fsmGettingMsg, 
  638.                 * where we could handle it gracefully by 
  639.                 * doing a MSGREJ, but this is such a bogus 
  640.                 * error that we'll just reset the
  641.                 * offender.
  642.                 */
  643.                 ddm_chip("***Illegal Disconnect attempt\n",
  644.                     1,2,3,4,5);
  645.                 IOLog("AMD53C974: Illegal disconnect attempt"
  646.                     " on target %d\n",
  647.                     activeCmd->scsiReq->target);
  648.                 [self hwAbort:SR_IOST_BV
  649.                     reason:NULL];
  650.                 return;
  651.             }
  652.             
  653.             /*
  654.              * Special tricky case here. Some targets fail to do
  655.              * a restore pointers before disconnect if all 
  656.              * requested data has been transferred. Do an 
  657.              * implied save ptrs if that's the case.
  658.              */
  659.             if(activeCmd->currentByteCount == 0) {
  660.                 activeCmd->savedPtr = activeCmd->currentPtr;
  661.                 activeCmd->savedByteCount = 
  662.                     activeCmd->currentByteCount;
  663.             }
  664.             scState = SCS_DISCONNECTED;
  665.             [self disconnect];
  666.             return;
  667.  
  668.         case MSG_SAVEPTRS:
  669.             activeCmd->savedPtr = activeCmd->currentPtr;
  670.             activeCmd->savedByteCount = 
  671.                 activeCmd->currentByteCount;
  672.             break;
  673.             
  674.         case MSG_RESTOREPTRS:
  675.             activeCmd->currentPtr = activeCmd->savedPtr;
  676.             activeCmd->currentByteCount = 
  677.                 activeCmd->savedByteCount;
  678.             break;
  679.                 
  680.         case MSG_MSGREJECT:
  681.             /*
  682.              * look at last message sent; may have to 
  683.              * disable sync or cmd queue mode for this target.
  684.              * This assumes that we don't send SDTR and queue tag
  685.              * in the same message.
  686.              */
  687.             ddm_chip("fsmAcceptingMsg: MESSAGE REJECT RECEIVED "
  688.                 "from target %d\n", 
  689.                 activeCmd->scsiReq->target, 2,3,4,5);
  690.             if(currMsgOutCnt == 0) {
  691.                 /*
  692.                  * Huh? We haven't sent a message recently...
  693.                  */
  694.                 [self hwAbort:SR_IOST_BV
  695.                     reason:"Unexpected Message Reject"];
  696.                 return;
  697.             }
  698.             switch(currMsgOut[0]) {
  699.             case MSG_SIMPLE_QUEUE_TAG:    
  700.                 [self disableMode:AM_CmdQueue];
  701.                 break;
  702.             case MSG_EXTENDED:
  703.                 /*
  704.                  * Only one we ever send is sync negotiation..
  705.                  */
  706.                 if(currMsgOut[2] == MSG_SDTR) {
  707.                     [self disableMode:AM_Sync];
  708.                 SDTR_State = SNS_NONE;
  709.                 break;
  710.                 }
  711.                 else {
  712.                 [self hwAbort:SR_IOST_INT
  713.                     reason:"Currupted Message Buffer"];
  714.                 return;
  715.                 }
  716.             default:
  717.                 IOLog("AMD53C974: %s Message Rejected\n",
  718.                     IOFindNameForValue(currMsgOut[0], 
  719.                     scsiMsgValues));
  720.                 /* oh well... */
  721.                 break;
  722.             }
  723.             
  724.             /*
  725.              * In any case, we're definitely thru with the 
  726.              * outbound message buffer.
  727.              */
  728.             currMsgOutCnt = 0;
  729.             break;
  730.             
  731.         case MSG_LNKCMDCMPLT:
  732.         case MSG_LNKCMDCMPLTFLAG:
  733.             /*
  734.              * This should never happen, because hwStart trashes
  735.              * commands with the LINK bit on.
  736.              */
  737.             [self hwAbort:SR_IOST_BV reason:"Linked command"];
  738.             return;
  739.             
  740.         case MSG_EXTENDED:
  741.             /*
  742.              * The only valid one is sync negotiation....
  743.              */
  744.             switch(currMsgIn[index+2]) {
  745.             case MSG_SDTR:
  746.                 if(currMsgIn[index+1] != (MSG_SDTR_LENGTH-2)) {
  747.                 [self hwAbort:SR_IOST_BV 
  748.                     reason:"Bad Extended Msg Length"];
  749.                 return;
  750.                 }
  751.                 switch(SDTR_State) {
  752.                     case SNS_HOST_INIT:
  753.                     /* 
  754.                      * Just completed SDTR that we initiated.
  755.                      */
  756.                     if([self parseSDTR:&currMsgIn[index]] 
  757.                             == NO) {
  758.                     [self hwAbort:SR_IOST_HW 
  759.                         reason:"Bad SDTR Parameters"];
  760.                     return;
  761.                     }
  762.                    
  763.                    /*
  764.                     * Successful SDTR. 
  765.                     */
  766.                     ddm_chip("host-init SDTR COMPLETE\n", 
  767.                     1,2,3,4,5);
  768.                     SDTR_State = SNS_NONE;
  769.                     break;
  770.                 
  771.                 case SNS_TARGET_INIT:
  772.                     /*
  773.                      * Target-initiated negotiation. This
  774.                      * was detected in fsmGettingMsg, where
  775.                      * we set ATN true.
  776.                      * Cons up a response and prime the message 
  777.                      * out state machine to send it.
  778.                      */
  779.                     [self createSDTR : currMsgOut
  780.                         inboundMsg : &currMsgIn[index]];
  781.                     currMsgOutCnt = MSG_SDTR_LENGTH;
  782.                     msgOutState = MOS_WAITING;
  783.                     
  784.                     /*
  785.                      * We have to load target context before 
  786.                      * we send the msg out in case of 
  787.                      * impending data in...
  788.                       */
  789.                     if([self parseSDTR:currMsgOut] == NO) {
  790.                         IOPanic("AMD53C974: SDTR "
  791.                             "Problem\n");
  792.                     }
  793.  
  794.                     break;
  795.                    
  796.                 default:
  797.                     IOPanic("AMD53C974: Bad SDTR_State");
  798.                 }
  799.                 
  800.                 /*
  801.                  * Skip over the rest of this message; index
  802.                  * should point to the last byte of this message.
  803.                  */
  804.                 index += (MSG_SDTR_LENGTH - 1);
  805.                 break;
  806.     
  807.             default:
  808.                 IOLog("AMD53C974: Unexpected Extended Message "
  809.                     "(0x%x) Received\n",
  810.                     currMsgIn[index+2]);
  811.                 [self hwAbort:SR_IOST_BV reason:NULL];
  812.                 return;
  813.             }    
  814.             break;
  815.                     
  816.         default:
  817.             /*
  818.              * all others are unacceptable. 
  819.              */
  820.             IOLog("AMD53C974: Illegal message (0x%x)\n", 
  821.                 currMsgIn[index]);
  822.             [self messageOut:MSG_MSGREJECT];
  823.         } 
  824.     } /* for index */
  825.     
  826.     /*
  827.      * Default case for 'break' from above switch - back to following 
  828.      * phase changes.
  829.      */
  830.     scState = SCS_INITIATOR;
  831. }
  832.  
  833. /*
  834.  * Just completed the SCMD_TRANSFER_INFO operation for message out. 
  835.  */
  836. - (void)fsmSendingMsg
  837. {
  838.     ddm_chip("fsmSendingMsg\n", 1,2,3,4,5);
  839.     ASSERT(activeCmd != NULL);
  840.     scState = SCS_INITIATOR;
  841.     if(SDTR_State == SNS_TARGET_INIT) {
  842.         /*
  843.          * If the message we just sent was a SDTR, we've just 
  844.          * completed a target-initiated SDTR sequence. 
  845.          * Note this assumes that an outbound SDTR in this 
  846.          * situation is the only message in currMsgOut[].
  847.          * This will have to change if we send a queue tag and
  848.          * SDTR in the sqame message.
  849.          */
  850.         if((currMsgOutCnt == MSG_SDTR_LENGTH) &&
  851.            (currMsgOut[0] == MSG_EXTENDED) &&
  852.            (currMsgOut[1] == (MSG_SDTR_LENGTH - 2)) &&
  853.            (currMsgOut[2] == MSG_SDTR)) {
  854.             
  855.              ddm_chip("fsmSendingMsg: target-init SDTR complete\n",
  856.                 1,2,3,4,5);
  857.             /*
  858.              * Note that we loaded target context before we 
  859.              * sent the msg out in case of impending data in...
  860.              */
  861.             SDTR_State = SNS_NONE;
  862.         }
  863.     }
  864. }
  865.  
  866.  
  867. /*
  868.  * Just completed the SCMD_TRANSFER_INFO operation for command.
  869.  */
  870. - (void)fsmSendingCmd
  871. {
  872.     ddm_chip("fsmSendingCmd\n", 1,2,3,4,5);
  873.     ASSERT(activeCmd != NULL);
  874.     scState = SCS_INITIATOR;
  875. }
  876.  
  877. /*
  878.  * Follow SCSI Phase change. Called while SCS_INITIATOR. 
  879.  */
  880. - (void)fsmPhaseChange
  881. {
  882.     int         phase;
  883.     char         *cp;
  884.     cdb_t         *cdbp;
  885.     int         i;
  886.     sc_status_t     rtn;
  887.     
  888.     ddm_chip("fsmPhaseChange\n", 1,2,3,4,5);
  889.     ASSERT(activeCmd != NULL);
  890.  
  891.     /*
  892.      * Advance msg out state machine -- SCSI spec says if
  893.      * we do a msg out phase and then see another phase
  894.      * we can assume msg was transmitted without error.
  895.      * However, if we're in msg in, we may have a message reject
  896.      * coming in, so we'll keep currMsgOut[] valid in that case.
  897.      *
  898.      * FIXME - one case which this would not cover is the queue tag
  899.      * message saved in currMsgOut[] during selection. We don't 
  900.      * go to MOS_SAWMSGOUT in that case. problem?
  901.      */
  902.     phase = saveStatus & SS_PHASEMASK;
  903.     if ((phase != PHASE_MSGOUT) &&
  904.         (phase != PHASE_MSGIN) &&
  905.         (msgOutState == MOS_SAWMSGOUT)) {
  906.         msgOutState = MOS_NONE;
  907.         currMsgOutCnt = 0;
  908.     }
  909.  
  910.     /*
  911.      * If we just sent a host-initiated SDTR and the target went 
  912.      * to something other than phase in, we assume that the negotiation
  913.      * failed. This is in violation of the spec, but the Sony CDROM 
  914.      * does this.
  915.      */
  916.     if((SDTR_State == SNS_HOST_INIT) && (phase != PHASE_MSGIN)) {
  917.         ddm_chip("IMPLIED SNS_HOST_INIT Reject\n", 1,2,3,4,5);
  918.                [self disableMode:AM_Sync];
  919.         SDTR_State = SNS_NONE;
  920.     }
  921.     
  922.     /* 
  923.      * make sure we start off with a clean slate.
  924.      *
  925.      * NO - this can disturb possible sync data in! We'll need to cover
  926.      * this in individual cases elsewhere...
  927.      */
  928.     /* WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO); */
  929.     ddm_chip("fsmPhaseChange:  phase = %s\n", 
  930.         IOFindNameForValue(phase, scsiPhaseValues), 2,3,4,5);
  931.  
  932.     switch (phase) {
  933.  
  934.         case PHASE_COMMAND:
  935.             /*
  936.          * The normal case here is after a host-initiated SDTR
  937.          * sequence. 
  938.          */
  939.         ddm_chip("fsmPhaseChange: command phase\n", 1,2,3,4,5);
  940.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  941.         cdbp = &activeCmd->scsiReq->cdb;
  942.         cp = (char *)cdbp;
  943.         for(i=0; i<activeCmd->cdbLength; i++) {
  944.             WRITE_REG(scsiFifo, *cp++);
  945.         }
  946.  
  947. #if    0
  948.         /*
  949.          * This causes extra bytes to sit around in the fifo
  950.          * if we go straight to data phase after this, and
  951.          * we can't clear the fifo at that time in case
  952.          * we're in sync data in...
  953.          */
  954.         /*
  955.          * fill fifo to avoid spurious command phase for target
  956.          * chips that try to get max command length
  957.          */
  958.         for (i = 12 - activeCmd->cdbLength; i > 0; i--)
  959.             WRITE_REG(scsiFifo, 0);
  960. #endif    0
  961.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  962.         scState = SCS_SENDINGCMD;
  963.         break;
  964.  
  965.         case PHASE_DATAOUT:    /* To Target from Initiator (write) */
  966.         if(activeCmd->scsiReq->read) {
  967.             [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
  968.             break;
  969.         }
  970.         if(rtn = [self dmaStart]) {
  971.             [self hwAbort:rtn 
  972.                 reason: IOFindNameForValue(rtn, 
  973.                     IOScStatusStrings)];
  974.             break;
  975.         }
  976.         break;
  977.         
  978.         case PHASE_DATAIN:    /* From Target to Initiator (read) */
  979.         if(!activeCmd->scsiReq->read) {
  980.             [self hwAbort:SR_IOST_BV reason:"bad i/o direction"];
  981.             break;
  982.         }
  983.         if(rtn = [self dmaStart]) {
  984.             [self hwAbort:rtn 
  985.                 reason: IOFindNameForValue(rtn, 
  986.                     IOScStatusStrings)];
  987.             break;
  988.         }
  989.         break;
  990.     
  991.         case PHASE_STATUS:    /* Status from Target to Initiator */
  992.         /*
  993.          * fsmCompleting will collect the STATUS byte
  994.          * (and hopefully a MSG) from the fifo when this
  995.          * completes.
  996.          */
  997.         scState = SCS_COMPLETING;
  998.         currMsgInCnt = 0;
  999.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  1000.         WRITE_REG(scsiCmd, SCMD_INIT_CMD_CMPLT);
  1001.         break;
  1002.         
  1003.         case PHASE_MSGIN:    /* Message from Target to Initiator */
  1004.         scState = SCS_GETTINGMSG;
  1005.         currMsgInCnt = 0;
  1006.         WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  1007.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  1008.         break;
  1009.         
  1010.         case PHASE_MSGOUT:    /* Message from Initiator to Target */
  1011.             WRITE_REG(scsiCmd, SCMD_CLEAR_FIFO);
  1012.         if(msgOutState == MOS_WAITING) {
  1013.             int i;
  1014.             
  1015.             ASSERT(currMsgOutCnt != 0);
  1016.             for(i=0; i<currMsgOutCnt; i++) {
  1017.                 ddm_chip("msg out: writing 0x%x\n",
  1018.                     currMsgOut[i], 2,3,4,5);
  1019.                 WRITE_REG(scsiFifo, currMsgOut[i]);
  1020.             }
  1021.             msgOutState = MOS_SAWMSGOUT;
  1022.             if(SDTR_State == SNS_HOST_INIT_NEEDED) {
  1023.                 /*
  1024.                  * sending SDTR message after select.
  1025.                  */
  1026.                 ASSERT(currMsgOut[0] == MSG_EXTENDED);
  1027.                 ASSERT(currMsgOut[2] == MSG_SDTR);
  1028.                 ASSERT(currMsgOutCnt == MSG_SDTR_LENGTH);
  1029.                 ddm_chip("going to SNS_HOST_INIT\n",
  1030.                     1,2,3,4,5);
  1031.                 SDTR_State = SNS_HOST_INIT;
  1032.             }
  1033.         } else {
  1034.             /*
  1035.              * Target went to msg out and we don't have
  1036.              * anything to send!  Just give it a nop.
  1037.              */
  1038.             ddm_chip("msg out: sending MSG_NOP\n", 1,2,3,4,5);
  1039.             WRITE_REG(scsiFifo, MSG_NOP);
  1040.         }
  1041.  
  1042.         scState = SCS_SENDINGMSG;
  1043.         /* 
  1044.          * ATN is automatically cleared when transfer info completes.
  1045.          */
  1046.         WRITE_REG(scsiCmd, SCMD_TRANSFER_INFO);
  1047.         break;
  1048.         
  1049.         default:
  1050.             [self hwAbort:SR_IOST_HW reason:"Bad SCSI phase"];
  1051.         break;
  1052.     }
  1053. }
  1054.  
  1055. /*
  1056.  * Set up to send single-byte message. 
  1057.  */ 
  1058. - (void) messageOut : (u_char)msg
  1059. {
  1060.     ddm_chip("messageOut (0x%x)\n", msg, 2,3,4,5);
  1061.     currMsgOut[0] = msg;
  1062.     currMsgOutCnt = 1;
  1063.     msgOutState = MOS_WAITING;
  1064.     WRITE_REG(scsiCmd, SCMD_SET_ATN);
  1065. }
  1066.  
  1067.  
  1068. /*
  1069.  * Load syncPeriod, syncOffset for activeCmd per perTarget values.
  1070.  */
  1071. - (void)targetContext : (unsigned) target
  1072. {
  1073.     perTargetData *perTargetPtr;
  1074.     
  1075.     perTargetPtr = &perTarget[target];
  1076.     if(!syncModeEnable || 
  1077.        perTargetPtr->syncDisable ||
  1078.        (perTargetPtr->syncXferOffset == 0)) {
  1079.         /*
  1080.          * Easy case, async.
  1081.          */
  1082.         WRITE_REG(syncOffset, 0);
  1083.         ddm_chip("targetContext(%d): ASYNC\n", target, 2,3,4,5);
  1084.         #ifdef    DEBUG
  1085.         syncOffsetShadow = 0;
  1086.         #endif    DEBUG
  1087.     }
  1088.     else {
  1089.         unsigned char periodReg;
  1090.         unsigned char offsetReg;
  1091.         
  1092.         periodReg = nsPeriodToSyncPeriodReg(
  1093.             perTargetPtr->syncXferPeriod,
  1094.             fastModeEnable, scsiClockRate);
  1095.         WRITE_REG(syncPeriod, periodReg);
  1096.         
  1097.         /*
  1098.          * FIXME - might eventually want to use non-default
  1099.          * values for RAD and RAA...
  1100.          */
  1101.         offsetReg = (perTargetPtr->syncXferOffset |
  1102.             SOR_RAD_DEFAULT | SOR_RAA_DEFAULT);
  1103.         WRITE_REG(syncOffset, offsetReg);
  1104.         ddm_chip("targetContext(%d): period 0x%x offset %d\n",
  1105.             target, periodReg, offsetReg, 4,5);
  1106.         #ifdef    DEBUG
  1107.         syncOffsetShadow = offsetReg;
  1108.         syncPeriodShadow = periodReg;
  1109.         #endif    DEBUG
  1110.     }
  1111. }
  1112.  
  1113. /*
  1114.  * Parse and validate 5-byte SDTR message. If valid, save in perTarget 
  1115.  * and in hardware. Returns YES if valid, else NO.
  1116.  * 
  1117.  * Specified message buffer could be from either currMsgIn[] or 
  1118.  * currMsgOut[].
  1119.  */
  1120. - (BOOL)parseSDTR    : (unsigned char *)sdtrMessage
  1121. {
  1122.     unsigned nsPeriod;
  1123.     unsigned char fastClock;
  1124.     unsigned minPeriod;
  1125.     perTargetData *perTargetPtr;
  1126.     
  1127.     ASSERT(activeCmd != NULL);
  1128.     perTargetPtr = &perTarget[activeCmd->scsiReq->target];
  1129.     
  1130.     if(sdtrMessage[0] != MSG_EXTENDED) {
  1131.         goto Bad;
  1132.     }
  1133.     if(sdtrMessage[1] != (MSG_SDTR_LENGTH - 2)) {
  1134.         goto Bad;
  1135.     }
  1136.     if(sdtrMessage[2] != MSG_SDTR) {
  1137.         goto Bad;
  1138.     }
  1139.     
  1140.     /*
  1141.      * period
  1142.      */
  1143.     nsPeriod = SDTR_TO_NS_PERIOD(sdtrMessage[3]);
  1144.     fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
  1145.     if(fastClock && fastModeEnable) {
  1146.         minPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
  1147.     }
  1148.     else {
  1149.         minPeriod = MIN_PERIOD_NORM;
  1150.     }
  1151.     if(nsPeriod < minPeriod) {
  1152.         goto Bad;
  1153.     }
  1154.     perTargetPtr->syncXferPeriod = nsPeriod;
  1155.     
  1156.     /*
  1157.      * Offset
  1158.      */
  1159.     if(sdtrMessage[4] > AMD_MAX_SYNC_OFFSET) {
  1160.         goto Bad;
  1161.     }
  1162.     perTargetPtr->syncXferOffset = sdtrMessage[4];
  1163.     
  1164.     /*
  1165.      * Success.
  1166.      */
  1167.     perTargetPtr->syncDisable = 0;
  1168.     perTargetPtr->syncNegotNeeded = 0;
  1169.     [self targetContext:activeCmd->scsiReq->target];
  1170.     
  1171.     ddm_chip("parseSDTR SUCCESS: %02x %02x %02x %02x %02x\n",
  1172.         sdtrMessage[0], sdtrMessage[1], sdtrMessage[2], 
  1173.         sdtrMessage[3], sdtrMessage[4]);
  1174.     ddm_chip("   period %d offset %d\n", perTargetPtr->syncXferPeriod,
  1175.         perTargetPtr->syncXferOffset, 3,4,5);
  1176.     return YES;
  1177.     
  1178. Bad:
  1179.     ddm_chip("parseSDTR FAIL: 02%x %02x %02x %02x %02x\n",
  1180.         sdtrMessage[0], sdtrMessage[1], sdtrMessage[2], 
  1181.         sdtrMessage[3], sdtrMessage[4]);
  1182.     return NO;
  1183. }
  1184.  
  1185. /*
  1186.  * Cons up a SDTR message appropriate for both our hardware and a possible
  1187.  * target-generated SDTR message. If inboundMsg is NULL, we just use
  1188.  * the parameters we want.
  1189.  */
  1190. - (void)createSDTR        : (unsigned char *)outboundMsg    // required
  1191.              inboundMsg : (unsigned char *)inboundMsg
  1192. {
  1193.     unsigned     desiredNsPeriod;
  1194.     unsigned     inboundNsPeriod;
  1195.     unsigned     offset = AMD_MAX_SYNC_OFFSET;
  1196.     unsigned char     fastClock;
  1197.     
  1198.     outboundMsg[0] = MSG_EXTENDED;
  1199.     outboundMsg[1] = MSG_SDTR_LENGTH - 2;
  1200.     outboundMsg[2] = MSG_SDTR;
  1201.     
  1202.     /*
  1203.      * period
  1204.      */
  1205.     fastClock = READ_REG(control3) & CR3_FAST_CLOCK;
  1206.     if(fastClock && fastModeEnable) {
  1207.         desiredNsPeriod = MIN_PERIOD_FASTCLK_FASTSCSI;
  1208.     }
  1209.     else {
  1210.         desiredNsPeriod = MIN_PERIOD_NORM;
  1211.     }
  1212.     if(inboundMsg) {
  1213.         inboundNsPeriod = SDTR_TO_NS_PERIOD(inboundMsg[3]);
  1214.     }
  1215.     else {
  1216.         inboundNsPeriod = desiredNsPeriod;
  1217.     }
  1218.     if(inboundNsPeriod > desiredNsPeriod) {
  1219.         /*
  1220.          * Target is slower than us
  1221.          */
  1222.         desiredNsPeriod = inboundNsPeriod;
  1223.     }
  1224.     outboundMsg[3] = NS_PERIOD_TO_SDTR(desiredNsPeriod);
  1225.     
  1226.     /*
  1227.      * Offset
  1228.      */
  1229.     if(inboundMsg) {
  1230.         offset = inboundMsg[4];
  1231.         if(offset > AMD_MAX_SYNC_OFFSET) {
  1232.             /* 
  1233.              * target's buffer smaller than ours
  1234.              */
  1235.             offset = AMD_MAX_SYNC_OFFSET;
  1236.         }
  1237.     }
  1238.     if(!syncModeEnable) {
  1239.         /*
  1240.          * Forget all of this. We won't do sync mode. 
  1241.          */
  1242.         offset = 0;
  1243.     }
  1244.     outboundMsg[4] = offset;
  1245.     
  1246.     ddm_chip("createSDTR: %02x %02x %02x %02x %02x\n",
  1247.         outboundMsg[0], outboundMsg[1], outboundMsg[2], 
  1248.         outboundMsg[3], outboundMsg[4]);
  1249.     ddm_chip("   period %d   offset %d\n", desiredNsPeriod, offset, 3,4,5);
  1250. }
  1251.  
  1252. /*
  1253.  * Disable specified mode for activeCmd's target. If mode is currently 
  1254.  * enabled, we'll log a message to the console.
  1255.  */
  1256. - (void)disableMode : (AMD_Mode)mode
  1257. {
  1258.     int target;
  1259.     perTargetData *perTargetPtr;
  1260.     const char *modeStr = NULL;
  1261.     
  1262.     ASSERT(activeCmd != NULL);
  1263.     target = activeCmd->scsiReq->target;
  1264.     perTargetPtr = &perTarget[target];
  1265.     switch(mode) {
  1266.         case AM_Sync:
  1267.             if(perTargetPtr->syncDisable == 0) {
  1268.             perTargetPtr->syncDisable = 1;
  1269.             modeStr = "Synchronous Transfer Mode";
  1270.         }
  1271.         [self targetContext:activeCmd->scsiReq->target];
  1272.         break;
  1273.         case AM_CmdQueue:
  1274.             if(perTargetPtr->cmdQueueDisable == 0) {
  1275.             perTargetPtr->cmdQueueDisable = 1;
  1276.             modeStr = "Command Queueing";
  1277.         }
  1278.         break;
  1279.     }
  1280.     ddm_chip("DISABLING %s for target %d\n", modeStr, target, 3,4,5);
  1281.     if(modeStr) {
  1282.         IOLog("AMD53C974: DISABLING %s for target %d\n", 
  1283.             modeStr, target);
  1284.     }
  1285. }
  1286.  
  1287. @end    /* AMD_SCSI(ChipPrivate) */
  1288.